﻿namespace OverStore.Runtime.ObjectRepository.Depot.IdentifierGenerator
{
    using System;
    using System.Diagnostics;

    /// <summary>
    /// ReadIdentifier generator uses user-defined delegate for obtain next identifier.
    /// </summary>
    /// <typeparam name="TInstance">The type of the instance.</typeparam>
    /// <typeparam name="TIdentifier">The type of the identifier.</typeparam>
    public sealed class DelegateIdentifierGenerator<TInstance, TIdentifier> : IIdentifierGenerator<TInstance, TIdentifier>
        where TInstance : class
    {
        private readonly Func<TInstance, TIdentifier, TIdentifier> _NextIdentifier;
        private TIdentifier _CurrentIdentifier;        

        /// <summary>
        /// Initializes a new instance of the <see cref="DelegateIdentifierGenerator{TInstance, TIdentifier}"/> class.
        /// </summary>
        /// <param name="nextIdentifierFunc">The next identifier func.</param>
        /// <param name="startingValue">The starting result.</param>
        public DelegateIdentifierGenerator(Func<TInstance, TIdentifier, TIdentifier> nextIdentifierFunc, TIdentifier startingValue)
        {
            if (nextIdentifierFunc == null)
                throw new ArgumentNullException("nextIdentifierFunc");
            _NextIdentifier = nextIdentifierFunc;
            _CurrentIdentifier = startingValue;
        }

        /// <summary>
        /// Obtain next identifier for specified instance.
        /// </summary>
        /// <param name="instance">The instance to obtain identifier for it.</param>
        /// <returns>
        /// The next result of identifier for specified instance.
        /// </returns>
        /// <exception cref="T:OverStore.Runtime.Repository.Depot.DepotException">The error occured due generating identifier.</exception>
        public TIdentifier NextIdentifier(TInstance instance)
        {
            Debug.Assert(instance != null, "Generating identifier for null instance.");
            _CurrentIdentifier = _NextIdentifier(instance, _CurrentIdentifier);
            return _CurrentIdentifier;
        }
    }
}
